/**
 * Project Name:UserServiceImpl
 * File Name:UserServiceImpl.java
 * Package Name:com.bwda.dsrs.systemservice.service
 * Date:2019年4月28日
 * Copyright (c) 2019, 江苏保旺达软件有限公司 All Rights Reserved.
 */
package com.bwda.dsrs.systemservice.service.impl;

import com.bwda.dsrs.base.centerbase.BaseContextHandler;
import com.bwda.dsrs.base.centerbase.util.PageHelperUtil;
import com.bwda.dsrs.base.util.Convert;
import com.bwda.dsrs.base.util.CopyUtil;
import com.bwda.dsrs.base.util.StringUtil;
import com.bwda.dsrs.systemservice.domain.Constants;
import com.bwda.dsrs.systemservice.domain.condition.datadict.DatadictCondition;
import com.bwda.dsrs.systemservice.domain.condition.user.UserCondition;
import com.bwda.dsrs.systemservice.domain.exception.SystemServiceException;
import com.bwda.dsrs.systemservice.domain.form.user.*;
import com.bwda.dsrs.systemservice.domain.po.datadict.DatadictPo;
import com.bwda.dsrs.systemservice.domain.po.pwdrule.PwdRulePo;
import com.bwda.dsrs.systemservice.domain.po.role.UserByRolePo;
import com.bwda.dsrs.systemservice.domain.po.user.UserPo;
import com.bwda.dsrs.systemservice.domain.po.usersecurity.UserSecurityPo;
import com.bwda.dsrs.systemservice.domain.vo.user.UserLoginVo;
import com.bwda.dsrs.systemservice.mapper.UserMapper;
import com.bwda.dsrs.systemservice.service.*;
import com.bwda.dsrs.systemservice.util.EncriptUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 用户菜单管理服务类
 *
 * @author youzhen
 * @date 2019年4月28日
 */
@Service
public class UserServiceImpl extends AbstractBaseServiceImpl<UserPo, UserCondition, UserMapper> implements UserService {

    @Resource
    private UserMapper userMapper;

    @Autowired
    private UserSynService userSynService;

    @Autowired
    private LoginRuleService loginRuleService;

    @Autowired
    private WeakPwdService weakPwdService;

    @Autowired
    private DatadictService datadictService;
    @Autowired
    private UserSecurityService userSecurityService;


    @Override
    public UserPo queryUserByUserCode(String userCode) throws SystemServiceException {
        UserCondition condition = new UserCondition();
        condition.setDelFlag(0);
        condition.setUserCode(userCode);
        List<UserPo> userPoList = userMapper.queryUserList(condition);
        if (userPoList.isEmpty()) {
            throw new SystemServiceException("用户名或者密码错误");
        }
        if (userPoList.size() > 1) {
            throw new SystemServiceException("用户信息不唯一");
        }
        UserPo userPo = userPoList.get(0);
        //平台用户需要初始化修改密码，同步用户无需修改
        String us = String.valueOf(userPo.getUserSource());
        if (StringUtils.isEmpty(userPo.getHisPwdOne()) && Constants.ONE_STR.equals(us)) {
            userPo.setPwdEdit(Constants.UpdateType.UPDATE);
        } else {
            userPo.setPwdEdit(Constants.UpdateType.NO_UPDATE);
        }
        return userPo;
    }

    @Override
    public UserPo queryUserByUserCodeForAop(String userCode) {
        return userMapper.queryUserByUserCodeForAop(userCode);
    }


    @Override
    public boolean updateState(String userIds, Long state) {
        Integer[] ids = Convert.toIntArray(userIds);
        List<Integer> userList = userMapper.queryUserState(ids);
        boolean result = userList.contains(Constants.QUIT_STATUS);
        if (result) {
            return false;
        } else {
            for (Integer userId : ids) {
                userMapper.updateState(userId, state);
                if(state.intValue()==Constants.NOT_DELETED){
                    //解锁，把失败次数
                    //用户安全策略不存在，则生成用户策略0
                    try {
                        UserPo userPo=   queryWithValid(userId);
                        UserSecurityPo userSecurityPo = userSecurityService.querySecurityByUserCode(userPo.getUserCode());
                        userSecurityPo.setLoginFailCount(0);
                        userSecurityService.update(userSecurityPo);
                    } catch (SystemServiceException e) {

                    }

                }
            }
            return true;
        }
    }

    @Override
    public UserQueryForm queryDetails(String userCode) {
        return userMapper.queryDetails(userCode);
    }

    @Override
    public void resetPassword(String ids, String password) throws SystemServiceException {
        Integer[] userIds = Convert.toIntArray(ids);
        for (Integer id : userIds) {
            UserPo userPo = this.query(id);
            String encodedPassword = "";
            //是否开启外部密码认证
            String outerPwdAuth = datadictService.getDataDictValByCode("root.outer.authway");
            //服务默认加密方式（未开启用户同步密码认证或者通过内部创建的用户）
            if (Constants.ZERO_STR.equals(outerPwdAuth) || Constants.ONE_INT.equals(userPo.getUserSource())) {
                //BCrypt强哈希方法进行加密
                BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
                encodedPassword = encoder.encode(password.trim());
            } else {
                //4a用户登录密码md5加密方式 0：密码直接md5,1：用户名+密码+密码随机数md5
                String loginMd5 = datadictService.getDataDictValByCode("root.loginMd5");
                String fullPwd = "";
                if (Constants.ZERO_STR.equals(loginMd5)) {
                    fullPwd = password;
                } else {
                    fullPwd = userPo.getUserCode() + password + userPo.getSalt();
                }
                encodedPassword = EncriptUtil.encodePwd(fullPwd);
            }
            userMapper.resetPassword(id, encodedPassword);
        }
    }

    /**
     * 导入用户数据
     *
     * @param userList 用户数据列表
     * @return 结果
     */
    @Override
    public String importUser(List<UserExcelImport> userList, String creatUserCode, int orgId) {
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        if (userList == null || userList.isEmpty()) {
            failureMsg.insert(0, "导入失败！数据为空");
            return failureMsg.toString();
        }
        for (UserExcelImport user : userList) {
            try {
                // 验证是否存在这个用户
                int count = this.checkUserCode(user.getUserCode());
                if (count < 1) {

                    if (!StringUtils.isEmpty(user.getUserName())) {
                        //BCrypt强哈希方法进行加密
                        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
                        if (StringUtils.isNotEmpty(user.getPassword())) {
                            user.setPassword(encoder.encode(user.getPassword().trim()));
                        }

                        userSynService.insertUser(user, creatUserCode, orgId);
                        successNum++;
                        successMsg.append("<br/>" + successNum + "、账号 " + user.getUserCode() + " 导入成功");
                    }
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserCode() + " 已存在");
                }
            } catch (Exception e) {
                e.printStackTrace();
                failureNum++;
                String msg = "<br/>" + failureNum + "、账号 " + user.getUserCode() + " 导入失败：";
                failureMsg.append(msg);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "导入失败！共 " + failureNum + " 条数据格式不正确");
            return failureMsg.toString();
        } else {
            successMsg.insert(0, "数据已全部导入成功！共 " + successNum + " 条");
            return successMsg.toString();
        }
    }

    @Override
    public void insertRole(UserRoleForm userRoleForm) {
        userMapper.insertRole(userRoleForm);
    }


    @Override
    public int deleteRole(String userCode) {
        return userMapper.deleteRole(userCode);
    }


    @Override
    public void insertUser(UserPo userPo) throws SystemServiceException {
        //是否开启外部密码认证
//        String outerPwdAuth = datadictService.getDataDictValByCode("root.outer.authway");
        //服务默认加密方式
        //BCrypt强哈希方法进行加密
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        userPo.setPassword(encoder.encode(userPo.getPassword().trim()));
        /*if (Constants.ZERO_STR.equals(outerPwdAuth) || Constants.ONE_INT.equals(userPo.getUserSource())) {
            //BCrypt强哈希方法进行加密
            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
            userPo.setPassword(encoder.encode(userPo.getPassword().trim()));
        } else {
            //4a用户登录密码md5加密方式 0：密码直接md5,1：用户名+密码+密码随机数md5
            String loginMd5 = datadictService.getDataDictValByCode("root.loginMd5");
            String fullPwdMd5 = "";
            String fullPwd = "";
            if (Constants.ZERO_STR.equals(loginMd5)) {
                fullPwd = userPo.getPassword().trim();
            } else {
                fullPwd = userPo.getUserCode() + userPo.getPassword().trim() + userPo.getSalt();
            }
            fullPwdMd5 = EncriptUtil.encodePwd(fullPwd);
            userPo.setPassword(fullPwdMd5);
        }*/

        userMapper.insert(userPo);
    }

    /**
     * 更新用户密码
     *
     * @param userPo
     */
    @Override
    public void updatePassword(UserPo userPo) {
        userMapper.updatePassword(userPo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean transferUserOrg(String userIds, Integer orgId) {
        Integer[] ids = Convert.toIntArray(userIds);
        List<Integer> orgIds = userMapper.queryOrgIds(ids);
        boolean result = orgIds.contains(orgId);
        if (result) {
            return false;
        } else {
            for (Integer id : ids) {
                userMapper.transferUserOrg(id, orgId);
            }
            return true;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUserByIds(String userId) {
        Integer[] userIds = Convert.toIntArray(userId);
        for (Integer userid : userIds) {
            userMapper.deleteUser(userid);
            String userCode = userMapper.queryCodeById(userid);
            if (userCode != null && !"".equals(userCode)) {
                userMapper.deleteRole(userCode);
                userMapper.deleteInfo(userCode);
            }
        }
    }

    @Override
    public List<UserForm> queryUserByCode(String userCodes) {
        String[] userIds = Convert.toStrArray(userCodes);
        return userMapper.queryUserByCode(userIds);
    }

    @Override
    public List<UserForm> queryUserByUserCodeList(String[] userCodeList) {
        return userMapper.queryUserByCode(userCodeList);
    }

    /**
     * 简单查询列表
     *
     * @param userCondition
     * @return
     */
    @Override
    public List<UserPo> selectSimpleList(UserCondition userCondition) {
        return userMapper.selectSimpleList(userCondition);
    }

    /**
     * 职级 记录 绑定/解绑
     *
     * @author liangjy
     */
    @Override
    public boolean updateLevelAndTitile(UserChangeLevelForm userChangeLevelForm) {
        //只能更新职级
        if (!Constants.UserLevelType.RANK.equals(userChangeLevelForm.getLevelType())) {
            return false;
        }
        userMapper.updateLevelAndTitile(userChangeLevelForm);
        return true;
    }

    @Override
    public List<UserForm> queryUser(UserForm userForm) {
        return userMapper.queryUser(userForm);
    }

    @Override
    public List<UserForm> queryByOrgIdUser(Integer orgId) {
        return userMapper.queryByOrgIdUser(orgId);
    }

    @Override
    public int checkUserCode(String userCode) {
        return userMapper.checkUserCode(userCode);
    }

    @Override
    public String queryOrgAdminCode(String userCode) {
        return userMapper.queryOrgAdminCode(userCode);
    }

    @Override
    public List<UserByRolePo> queryUserByIncludeLevel(UserCondition userCondition) {
        PageHelperUtil.startPage(userCondition.getPageNum(), userCondition.getPageSize());
        List<UserPo> userPoList = userMapper.queryUserByIncludeLevel(userCondition);
        List<UserByRolePo> userByRolePoList = new ArrayList<UserByRolePo>();
        for (UserPo userPo : userPoList) {
            userByRolePoList.add(this.getUserConditionByUserPo(userPo));
        }
        return userByRolePoList;
    }

    @Override
    public int queryUserByIncludeLevelCount(UserCondition userCondition) {
        int count = userMapper.queryUserByIncludeLevelCount(userCondition);
        return count;
    }

    @Override
    public List<UserPo> queryUserByGroupId(UserCondition userCondition) {
        List<UserPo> userPoList = new ArrayList<UserPo>();
        int count = this.queryCount(userCondition);
        if (count > Constants.NOT_DELETED) {
            userPoList = userMapper.queryUserByGroupId(userCondition);
        }
        return userPoList;
    }

    @Override
    public List<UserPo> queryUserByOrgId(UserCondition condition) {
        PageHelperUtil.startPage(condition.getPageNum(), condition.getPageSize());
        return userMapper.queryUserByOrgId(condition);
    }

    @Override
    public int queryUserByOrgIdCount(UserCondition condition) {
        return userMapper.queryUserByOrgIdCount(condition);
    }

    @Override
    public boolean checkPwdFormat(String userCode, String confirmPwd) throws SystemServiceException {
        PwdRulePo pwdRulePo = loginRuleService.queryWithValid(Constants.ONE_INT);
        if (confirmPwd.trim().length() > pwdRulePo.getMaxLength() || confirmPwd.trim().length() < pwdRulePo.getMinLength()) {
            throw new SystemServiceException("密码长度设置在" + pwdRulePo.getMinLength() + "-" + pwdRulePo.getMaxLength() + "之间");
        }
        //获取登录策略
        if (Constants.ONE_INT.equals(pwdRulePo.getHasLower())) {
            if (!StringUtil.constainLowercase(confirmPwd)) {
                throw new SystemServiceException("密码需含有小写字母");
            }
        }
        if (Constants.ONE_INT.equals(pwdRulePo.getHasUpper())) {
            if (!StringUtil.constainUppercase(confirmPwd)) {
                throw new SystemServiceException("密码需含有大写字母");
            }
        }
        if (Constants.ONE_INT.equals(pwdRulePo.getHasNumber())) {
            if (!StringUtil.constainNum(confirmPwd)) {
                throw new SystemServiceException("密码需含有数字");
            }
        }
        if (Constants.ONE_INT.equals(pwdRulePo.getHasSpecial())) {
            if (!StringUtil.constainSpecialCase(confirmPwd)) {
                throw new SystemServiceException("密码需含有特殊字符");
            }
        }
        if (Constants.ZERO_INT.equals(pwdRulePo.getHasUserName())) {
            if (confirmPwd.toLowerCase().contains(BaseContextHandler.getUserCode())) {
                throw new SystemServiceException("密码不可包含用户名");
            }
        }
        /**校验密码是否存在连续数字或者字母*/
        if (StringUtil.checkSeriesChar(confirmPwd, pwdRulePo.getContinuousLength())) {
            throw new SystemServiceException("密码不能为" + pwdRulePo.getContinuousLength() + "位连续数字或者字母");
        }
        if (Constants.ONE_INT.equals(pwdRulePo.getIsWeakPwdCheck())) {
            checkWeakPwd(confirmPwd);
        }
        if (pwdRulePo.getHistoryPwdTime() > Constants.ZERO_INT) {
//            UserPo userPo = this.queryUserByUserCode(userCode);
            if (pwdRulePo.getHistoryPwdTime().equals(Constants.ONE_INT)) {
                checkHistoryPwd(userCode, confirmPwd, Constants.ONE_INT);
            } else if (pwdRulePo.getHistoryPwdTime().equals(Constants.TWO_INT)) {
                checkHistoryPwd(userCode, confirmPwd, Constants.TWO_INT);
            }
        }
        return true;
    }


    /**
     * 检测是否包含弱密码
     *
     * @param userCode     用户code
     * @param confirmPwd   解密后的密码
     * @param compareValue
     * @return
     */
    private void checkHistoryPwd(String userCode, String confirmPwd, int compareValue) throws SystemServiceException {
        UserPo userPo = this.queryUserByUserCode(userCode);
        //是否开启外部密码认证
        String outerPwdAuth = datadictService.getDataDictValByCode("root.outer.authway");
        //服务默认加密方式（未开启用户同步密码认证或者通过内部创建的用户）
        if (Constants.ZERO_STR.equals(outerPwdAuth) || Constants.ONE_INT.equals(userPo.getUserSource())) {
            //BCrypt强哈希方法进行加密
            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
            if (compareValue == Constants.ONE_INT) {
                //验证修改密码与数据库历史密码是否一致
                if (StringUtils.isNotBlank(userPo.getHisPwdOne()) && encoder.matches(confirmPwd, userPo.getHisPwdOne())) {
                    throw new SystemServiceException("密码不可与历史密码相同");
                }
            } else {
                //验证修改密码与数据库历史密码是否一致
                boolean result = StringUtils.isNotBlank(userPo.getHisPwdOne()) && encoder.matches(confirmPwd, userPo.getHisPwdOne().trim());
                boolean res = StringUtils.isNotBlank(userPo.getHisPwdOtwo()) && encoder.matches(confirmPwd, userPo.getHisPwdOtwo().trim());
                if ( result  || res) {
                    throw new SystemServiceException("密码不可与历史密码相同");
                }
            }
        } else {
            //4a用户登录密码md5加密方式 0：密码直接md5,1：用户名+密码+密码随机数md5
            String loginMd5 = datadictService.getDataDictValByCode("root.loginMd5");
            String fullPwdMd5 = "";
            String fullPwd = "";
            if (Constants.ZERO_STR.equals(loginMd5)) {
                fullPwd = confirmPwd;
            } else {
                fullPwd = userCode + confirmPwd + userPo.getSalt();
            }
            fullPwdMd5 = EncriptUtil.encodePwd(fullPwd);
            if (compareValue == Constants.ONE_INT) {
                if (StringUtils.isNotBlank(userPo.getHisPwdOne()) && userPo.getHisPwdOne().equals(fullPwdMd5)) {
                    throw new SystemServiceException("密码不可与历史密码相同");
                }
            } else {
                boolean result = StringUtils.isNotBlank(userPo.getHisPwdOne()) && userPo.getHisPwdOne().equals(fullPwdMd5);
                boolean res = StringUtils.isNotBlank(userPo.getHisPwdOtwo()) && userPo.getHisPwdOtwo().equals(fullPwdMd5);
                if (result || res) {
                    throw new SystemServiceException("密码不可与历史密码相同");
                }
            }
        }
    }

    private UserByRolePo getUserConditionByUserPo(UserPo userPo) {
        UserByRolePo userByRolePo = CopyUtil.transfer(userPo, UserByRolePo.class);
        return userByRolePo;
    }

    @Override
    public int checkPhoneUnique(String phone, Integer typeId, String userCode) {
        if (Constants.TYPE_ID.equals(typeId)) {
            return userMapper.checkPhoneUnique(phone);
        } else {
            return userMapper.checkPhoneUniqueUpdate(phone, userCode);
        }
    }

    @Override
    public int checkIdnumberUnique(String idnumber, Integer typeId, String userCode) {
        if (Constants.TYPE_ID.equals(typeId)) {
            return userMapper.checkIdnumberUnique(idnumber);
        } else {
            return userMapper.checkIdnumberUniqueUpdate(idnumber, userCode);
        }
    }

    @Override
    public int checkEmailUnique(String email, Integer typeId, String userCode) {
        if (Constants.TYPE_ID.equals(typeId)) {
            return userMapper.checkEmailUnique(email);
        } else {
            return userMapper.checkEmailUniqueUpdate(email, userCode);
        }
    }

    @Override
    public List<UserLoginVo> queryUserLoginTime() {
        return userMapper.queryUserLoginTime();
    }

    @Override
    public void updateUserState(Integer userId) {
        userMapper.updateUserState(userId);
    }

    @Override
    public UserLoginVo checkPwd(String userCode) {
        return userMapper.checkPwd(userCode);
    }

    @Override
    public void updateLockDate(String userCode) {
        userMapper.updateLockDate(userCode);
    }

    @Override
    public List<UserLoginVo> queryLockTime() {
        return userMapper.queryLockTime();
    }

//    检测弱密码

    /**
     * 检测是否包含弱密码
     *
     * @param password 解密后的密码
     * @return
     */
    private void checkWeakPwd(String password) throws SystemServiceException {
        DatadictCondition condition = new DatadictCondition();
        condition.setPageNum(0);
        condition.setPageSize(Integer.MAX_VALUE);
        condition.setDelFlag(Constants.NOT_DELETED);
        condition.setDataDictTypeCode(Constants.WEAK_DICT_TYPE);
        List<DatadictPo> poList = datadictService.queryList(condition);
        for (DatadictPo po : poList) {
            if (password.contains(po.getDataDictValue())) {
                throw new SystemServiceException("密码包含弱字符串");
            }
        }
    }


    @Override
    public boolean checkUserIsTq(String userCode) {
        boolean flag = false;
        int count = this.getMapper().checkUserIsTq(userCode);
        if (count != 0) {
            flag = true;
        }
        return flag;
    }

    @Override
    public List<UserPo> selectListForLevelScore(UserCondition var1) {
        return this.getMapper().selectListForLevelScore(var1);
    }

    @Override
    public List<UserPo> selectListForRoleId(Integer roleId) {
        return this.getMapper().selectListForRoleId(roleId);
    }

    @Override
    public List<UserPo> queryUserForm(FileSpaceSettingQueryForm userForm) {
        return userMapper.queryUserForm(userForm);
    }

    @Override
    public int queryUserFormCount(FileSpaceSettingQueryForm userForm) {
        return userMapper.queryUserFormCount(userForm);
    }
}
